{{ NordicPlusMultiTarget110714a

  modified from dwd_nRF24L01Beta110629a
  110713a go back to just one address for all
  units.
  The units will need to use timing to keep from transmitting over
  the top of each other.
  Change name from NordicPlusMultiTarget110714a to
  NordicBeta110718a
  
}}
CON
  ' DWD These constants where in the original object.
  ' DWD Not many are used.

  
  'nRF24L01 constants:
  
  'Commands
  R_REGISTER = %0000_0000 '+ reg
  W_REGISTER = %0010_0000 '+ reg  $20
  R_RX_PAYLOAD = %0110_0001     ' $61
  W_TX_PAYLOAD = %1010_0000     ' $A0
  FLUSH_TX = %1110_0001         ' $E1
  FLUSH_RX = %1110_0010         ' $E2
  REUSE_TX_PL = %1110_0011      ' $E3
  R_RX_PL_WID = %0110_0000      ' $30
  W_ACK_PAYLOAD = %1010_1000 '+ pipe  ' $A8
  W_TX_PAYLOAD_NOACK = %1011_0000 ' $B0
  NOOP = %1111_1111             ' $FF
                                
  'Registers
  CONFIG = $00   '%0000_1000 / $08
  EN_AA = $01  '%0011_1111  / $3F
  EN_RXADDR = $02  '%0000_0011
  SETUP_AW = $03   '%0000_0011
  SETUP_RETR = $04  '%0000_0011
  RF_CH = $05   '%0000_0010
  RF_SETUP = $06  '%0000_1110
  _STATUS = $07     '%0000_1110 / $E 
  OBSERVE_TX = $08  '%0000_0000
  RPD = $09   '%0000_0000 
  RX_ADDR_P0 = $0A '$E7E7E7E7E7
  RX_ADDR_P1 = $0B '$C2C2C2C2C2
  RX_ADDR_P2 = $0C  '$C3
  RX_ADDR_P3 = $0D  '$C4 
  RX_ADDR_P4 = $0E  '$C5 
  RX_ADDR_P5 = $0F  '$C6 
  TX_ADDR = $10    '$E7E7E7E7E7
  RX_PW_P0 = $11   '%0000_0000
  RX_PW_P1 = $12   '%0000_0000 
  RX_PW_P2 = $13   '%0000_0000 
  RX_PW_P3 = $14  '%0000_0000 
  RX_PW_P4 = $15  '%0000_0000 
  RX_PW_P5 = $16  '%0000_0000 
  FIFO_STATUS = $17 '%0001_0001 
  DYNPD = $1C   '%0000_0000
  FEATURE = $1D  '%0000_0000


  _LargestPayloadSize = 32
  _DefaultPayloadSize = _LargestPayloadSize

  _AddressSizeOffset = 3
  _StatusnOffset = 7
  _PayloadOffset = 8
  _RxAddressOffset = 9
  _DynamicPL = 10
  _Feature = 11


        
OBJ 

  Spi : "dwd_nordicSpi110416a"
  Header : "PanicHeader110717a"
  
VAR

  long configPtr
  
  byte SpiSck
  byte SpiMiso                
  byte SpiMosi 
  byte SpiCsn    
  byte SpiCe
  
  byte payloadSize, globalAddressSize
  byte statusReset
  'byte deviceId, previousTarget
  'byte txAddressInitial[5], txAddressTarget[5]  
  byte rxAddress[5]  
  byte txAddress[5]  

PUB Start(sck, miso, mosi, csn, ce, configPtr_) | localIndex
'' configPtr_ points to the location of start up parameters.
'' This pointer can be changed with the config method.
'' statusPtr_ points to the location of a byte used to clear the status register.
'' configPtr_ points to the location of the rx address the tx address should be five
'' bytes after this location.

  result := Spi.Start(miso, mosi, sck) - 1
            
  SpiSck := sck
  SpiMiso := miso
  SpiMosi := mosi 
  SpiCsn := csn     
  SpiCe := ce
  'previousTarget := deviceId := deviceId_
  ' set previousTarget to deviceId to make sure txAddress gets changed
  ' for first tx
  configPtr := configPtr_
  'statusPtr := statusPtr_
  'addressPtr := addressPtr_
  
  'SetAddress(deviceId, @rxAddress)
    
  outa[SpiSck]~
  outa[SpiMosi]~
  outa[SpiCsn]~~                          ' chip select not, active low
  outa[SpiCe]~
  
  dira[SpiSck]~~
  dira[SpiMosi]~~
  dira[SpiCsn]~~
  dira[SpiCe]~~

  
  'Configure for receive          
  Configure(configPtr_)
  
PUB Configure(localPtr) | localIndex
{{
  Configure nRF24L01 registers for receive mode.
  Using data at location "localPtr" provided
  by parent object.
  The data should be arranged so the first seven bytes starting
  at localPtr  contain data to be written to the first seven
  registers of this device.  The eight byte should be payload
  size.  The nineth byte should be the start of the RX address
  followed by the TX address.
  To change the configuration, either the data in the parent object
  could be overwritten with the new desired data or a pointer
  to a different set of data could be used as the parameter
  when calling this object.  
 
}}
  ' Load global variables with requently used data.
  
  configPtr := localPtr
  'payloadSize := byte[configPtr + Header#_PayloadOffset] '_payloadSize
  statusReset := byte[configPtr + Header#_StatusOffset]

  globalAddressSize := byte[configPtr + Header#_AddressSizeOffset]
  globalAddressSize += 2
  globalAddressSize <#= 5
  globalAddressSize #>= 3            
              
  repeat localIndex from 0 to globalAddressSize - 1
    rxAddress[localIndex] := byte[configPtr + Header#_RxAddressOffset + localIndex]
    txAddress[localIndex] := byte[configPtr + Header#_RxAddressOffset + globalAddressSize + localIndex]

  ' Write the registers with the new data.
  outa[SpiCe]~
   
   
  outa[SpiCsn]~   
  SpiWrite(W_REGISTER + EN_AA)
  SpiWrite(byte[localPtr + EN_AA])
  outa[SpiCsn]~~
   
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + SETUP_RETR)
  SpiWrite(byte[localPtr + SETUP_RETR])    
  outa[SpiCsn]~~    
  
  outa[SpiCsn]~  
  SpiWrite(W_REGISTER + SETUP_AW)   
  SpiWrite(byte[localPtr + SETUP_AW])   
  outa[SpiCsn]~~    
  
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + RF_SETUP) 
  SpiWrite(byte[localPtr + RF_SETUP])  
  outa[SpiCsn]~~

  'outa[SpiCsn]~
  'SpiWrite(W_REGISTER + RX_PW_P0) 
  'SpiWrite(payloadSize)
  'outa[SpiCsn]~~   
  
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + RF_CH)
  SpiWrite(byte[localPtr + RF_CH]) ' *** this is different than earlier driver  
  outa[SpiCsn]~~                    ' I think it fixes a bug that kept it from communicating
                                    ' with the older modules.
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + RX_ADDR_P0)
  repeat localIndex from 0 to globalAddressSize - 1
    SpiWrite(rxAddress[localIndex]) 
  outa[SpiCsn]~~
  
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + TX_ADDR)
  repeat localIndex from 0 to globalAddressSize - 1
    SpiWrite(txAddress[localIndex]) 
  outa[SpiCsn]~~  

  outa[SpiCsn]~  
  SpiWrite(W_REGISTER + CONFIG)
  SpiWrite(byte[localPtr])
  outa[SpiCsn]~~

  outa[SpiCsn]~
  SpiWrite(W_REGISTER + DYNPD)
  SpiWrite(byte[configPtr + _DynamicPL])
  outa[SpiCsn]~~ 
  
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + FEATURE)
  SpiWrite(byte[configPtr + _Feature])
  outa[SpiCsn]~~ 
  
    
  'Start receiving
  outa[SpiCe]~~

PUB ReadPayload(stringToFillPtr) | localIndex
{{
  Reads payload from nRF24L01.
  Also flushes RX FIFO and resets IRQ state
}}    

  'Stop receiving
  outa[SpiCe]~

  'Determine RX Payload size.
  outa[SpiCsn]~
  SpiWrite(R_RX_PL_WID) ' -or-?(R_REGISTER + RX_PW_P0)
  payloadSize := SpiRead
  outa[SpiCsn]~~
    
  'Read RX payload   
  outa[SpiCsn]~    
  SpiWrite(R_RX_PAYLOAD)   
  Spi.ShiftInStr(stringToFillPtr, payloadSize)
  outa[SpiCsn]~~

  if payloadSize > 32  
    'Flush RX FIFO    
    outa[SpiCsn]~
    SpiWrite(FLUSH_RX)    
    outa[SpiCsn]~~

  'Reset IRQ 
  { Remiving this since Nordic Object will handle IRQs
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + _STATUS)
  SpiWrite(statusReset)   
  outa[SpiCsn]~~
  }
  'Start receiving
  outa[SpiCe]~~

PRI SpiRead

  'outa[SpiMOSI]~~               ' write a NOOP as data is read
  result := Spi.ShiftIn
  'outa[SpiMOSI]~
   
PUB SpiReadPub(localCommand, localPtr, bytesToRead)

  outa[SpiCsn]~
  SpiWrite(localCommand)
  Spi.ShiftInStr(localPtr, bytesToRead) 
  outa[SpiCsn]~~
   
PRI SpiWrite(byteOut)

  Spi.ShiftOut(byteOut)
   
PUB SpiWritePub(localRegister, localPtr, bytesToWrite) 

  outa[SpiCsn]~ 
  SpiWrite(localRegister + W_REGISTER)
  Spi.ShiftOutStr(localPtr, bytesToWrite)
  outa[SpiCsn]~~

PUB GetStatus

  outa[SpiCsn]~  
  result := SpiRead
  outa[SpiCsn]~~

PUB FlushTX
  
  outa[SpiCsn]~
  SpiWrite(FLUSH_TX)
  outa[SpiCsn]~~
  
PUB GetFIFOStatus

  outa[SpiCsn]~
  SpiWrite(R_REGISTER + FIFO_STATUS)
  result := SpiRead
  outa[SpiCsn]~~

PUB GetObserveTX

  outa[SpiCsn]~
  SpiWrite(R_REGISTER + OBSERVE_TX)
  result := SpiRead
  outa[SpiCsn]~~
  
PUB SetStatus(status)
  'outa[SpiCe]~
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + _STATUS)
  SpiWrite(status)
  outa[SpiCsn]~~
  'outa[SpiCe]~~
  
PUB TransmitString(localPtr) | localIndex
'' For now this method transmit the a full payload of bytes starting with
'' the memory location "localPtr".
'' I'd like to add the ability to transmit strings larger than the
'' payload size.  I'll need to be about to use the auto retransmit
'' ability of the new modules.  I also want to come up with a system
'' of acknowledging packets when using older modules.
  {if localTarget <> previousTarget
    SetAddress(targetId, @txAddressTarget)
    previousTarget := localTarget
   } 
  outa[SpiCe]~
  'Take out of rx mode

  outa[SpiCsn]~
  SpiWrite(W_REGISTER + _STATUS)
  SpiWrite(statusReset)
  outa[SpiCsn]~~

  outa[SpiCsn]~
  SpiWrite(W_REGISTER + CONFIG)
  SpiWrite(byte[configPtr] - 1) ' PTX mode
  outa[SpiCsn]~~

  outa[SpiCsn]~
  SpiWrite(FLUSH_TX)
  outa[SpiCsn]~~

  outa[SpiCsn]~
  SpiWrite(W_TX_PAYLOAD)
  Spi.ShiftOutStr(localPtr, payloadSize)  
  outa[SpiCsn]~~

  outa[SpiCe]~~
  waitcnt(1000 + cnt)           ' > 10us 800 = 10 us @ 80MHz
  outa[SpiCe]~                  ' Spin might be slow enough not to need a delay

  outa[SpiCsn]~
  SpiWrite(W_REGISTER + TX_ADDR) ' I shouldn't need to do this. Now I do.
  repeat localIndex from 0 to 4                         ' I set this in the config method
    SpiWrite(txAddress[localIndex])  ' **** test to see if this still works
  outa[SpiCsn]~~                     ' **** with address write removed
  
  outa[SpiCsn]~ 
  SpiWrite(W_REGISTER + CONFIG)
  SpiWrite(byte[configPtr])
  outa[SpiCsn]~~
    
  'Start receiving
  outa[SpiCe]~~

PUB Transmit(addr, data, length) | localIndex
'' This is Only used by PTX unit!!!

  outa[SpiCe]~  'Take out of rx mode  
  

  'outa[SpiCsn]~
  'SpiWrite(W_REGISTER + _STATUS)
  'SpiWrite(statusReset)
  'outa[SpiCsn]~~

  'outa[SpiCsn]~
  'SpiWrite(W_REGISTER + CONFIG)
  'SpiWrite(byte[configPtr] - 1) ' PTX mode
  'outa[SpiCsn]~~

  'outa[SpiCsn]~
  'SpiWrite(FLUSH_TX)
  'outa[SpiCsn]~~

  
  outa[SpiCsn]~
  SpiWrite(W_REGISTER + TX_ADDR) ' Set the address of the destination PRX
  repeat localIndex from 0 to globalAddressSize-1' 
    SpiWrite(byte [addr][localIndex])
  outa[SpiCsn]~~ 

  outa[SpiCsn]~
  SpiWrite(W_REGISTER + RX_ADDR_P0) ' Set the PTX's RX address to accept ACK from PRX.
  repeat localIndex from 0 to globalAddressSize-1
    SpiWrite(byte [addr][localIndex]) 
  outa[SpiCsn]~~                 

    
  outa[SpiCsn]~          'Write to the TX FIFO
  SpiWrite(W_TX_PAYLOAD)
  Spi.ShiftOutStr(@data, length)  
  outa[SpiCsn]~~

  outa[SpiCe]~~    ' PULSE CE to enable TX mode on Nordic
  waitcnt(1000 + cnt)           ' > 10us 800 = 10 us @ 80MHz
  outa[SpiCe]~                  ' Spin might be slow enough not to need a delay

  outa[SpiCsn]~
  SpiWrite(W_REGISTER + TX_ADDR) ' I shouldn't need to do this. Now I do.
  repeat localIndex from 0 to 4                         ' I set this in the config method
    SpiWrite(txAddress[localIndex])  ' **** test to see if this still works
  outa[SpiCsn]~~                     ' **** with address write removed
  
  'outa[SpiCsn]~ 
  'SpiWrite(W_REGISTER + CONFIG)
  'SpiWrite(byte[configPtr])
  'outa[SpiCsn]~~
    
  'Start receiving
  'outa[SpiCe]~~

PUB TransmitAck(pipe, data, length) | localIndex
'' This is Only used by PRX unit!!!
  pipe := 0  
  outa[SpiCsn]~          'Write to the TX FIFO
  SpiWrite(W_ACK_PAYLOAD + pipe)
  Spi.ShiftOutStr(@data, length)  
  outa[SpiCsn]~~


   
{PRI SetAddress(targetId, localPtr) | localIndex
'' This method modifies addressInitial and makes a unique address
'' base on the target device's ID.
'' Add devices need to use this same algorithm for
'' modifying addresses.  The all also need to fill
'' addressInitial with the same set of numbers.

  repeat localIndex from 0 to 4
    byte[localIndex] := addressInitial[localIndex] 
    if localIndex == 0 or localIndex == 4
      byte[localIndex] += targetId
}      